package com.cqs.leetcode.ds.search;

import com.cqs.leetcode.ds.ArraysUtils;
import com.cqs.leetcode.ds.sort.ISort;
import com.cqs.leetcode.ds.sort.MergeSort;

import java.util.Random;

/**
 * Author:li
 * <p>
 * create date: 18-5-30 09:27
 */
public class BinarySearch {


    /**
     * 查询target在有序数组sort中首次出现的位置 若不存在返回-1
     *
     * @param sort
     * @param target
     * @return
     */
    public int searchFirst(int[] sort, int target) {
        if (sort == null || sort.length == 0) return -1;
        int left = 0, right = sort.length - 1, mid = (left + right) / 2;
        do {
            if (target == sort[mid]) {
                //mid一定会大于等于left
                if (mid == left || sort[mid - 1] != target) return mid;
                right = mid - 1;
            } else if (target < sort[mid]) {
                right = mid - 1;
            } else {
                left = mid + 1;
            }
            mid = (left + right) / 2;
        } while (left <= right);
        return -1;
    }

    /**
     * 查询target在有序数组sort中最后一次出现的位置 若不存在返回-1
     *
     * @param sort
     * @param target
     * @return
     */
    public int searchLast(int[] sort, int target) {
        if (sort == null || sort.length == 0) return -1;
        int left = 0, right = sort.length - 1, mid = (left + right) / 2;
        do {
            if (target == sort[mid]) {
                //mid一定会小于等于right
                if (mid == right || sort[mid + 1] != target) return mid;
                left = mid + 1;
            } else if (target < sort[mid]) {
                right = mid - 1;
            } else {
                left = mid + 1;
            }
            mid = (left + right) / 2;
        } while (left <= right);
        return -1;
    }


    /**
     * 基于循环实现二分查找
     *
     * @param sort
     * @param target
     * @return
     */
    public int search0(int[] sort, int target) {
        if (sort == null || sort.length == 0) return -1;
        int left = 0, right = sort.length - 1, mid = (left + right) / 2;
        do {
            if (target == sort[mid]) {
                return mid;
            }
            if (target < sort[mid]) {
                right = mid - 1;
            } else {
                left = mid + 1;
            }
            mid = (left + right) / 2;
        } while (left <= right);
        return -1;
    }

    /**
     * 递归实现二分查找
     *
     * @param sort
     * @param target
     * @return
     */
    public int search(int[] sort, int target) {
        if (sort == null || sort.length == 0) return -1;
        return search(sort, 0, sort.length - 1, target);
    }

    private int search(int[] sort, int left, int right, int target) {
        if (left > right) return -1;
        int mid = (left + right) / 2;
        if (target == sort[mid]) {
            return mid;
        }
        if (target < sort[mid]) {
            return search(sort, left, mid - 1, target);
        }
        return search(sort, mid + 1, right, target);
    }


    public static void main(String[] args) {
        BinarySearch bs = new BinarySearch();
        ISort sort = new MergeSort();
        int[] nums = ArraysUtils.randInts(30);
//        int[] nums = {0, 1, 2, 5, 5, 5, 6, 6, 7, 8};
        sort.sort(nums);
        //有序数组
        ArraysUtils.print(nums);
        int idx = new Random().nextInt(nums.length);
//        idx = 5;
        int target = nums[idx];
        System.out.println("target:" + nums[idx]);
        System.out.println("index: " + idx + "\t" + bs.search(nums, target) + "\t" + bs.search0(nums, target)
                + "\t首次位置:" + bs.searchFirst(nums, target) + "\t最后位置:" + bs.searchLast(nums, target));
    }
}
